##// END OF EJS Templates
Adding v2 nbformat back in.
Brian Granger -
Show More
@@ -0,0 +1,78 b''
1 """The main API for the v2 notebook format.
2
3 Authors:
4
5 * Brian Granger
6 """
7
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
18
19 from .nbbase import (
20 NotebookNode,
21 new_code_cell, new_text_cell, new_notebook, new_output, new_worksheet,
22 new_metadata, new_author
23 )
24
25 from .nbjson import reads as reads_json, writes as writes_json
26 from .nbjson import reads as read_json, writes as write_json
27 from .nbjson import to_notebook as to_notebook_json
28
29 from .nbxml import reads as reads_xml
30 from .nbxml import reads as read_xml
31 from .nbxml import to_notebook as to_notebook_xml
32
33 from .nbpy import reads as reads_py, writes as writes_py
34 from .nbpy import reads as read_py, writes as write_py
35 from .nbpy import to_notebook as to_notebook_py
36
37 from .convert import convert_to_this_nbformat
38
39 #-----------------------------------------------------------------------------
40 # Code
41 #-----------------------------------------------------------------------------
42
43 def parse_filename(fname):
44 """Parse a notebook filename.
45
46 This function takes a notebook filename and returns the notebook
47 format (json/py) and the notebook name. This logic can be
48 summarized as follows:
49
50 * notebook.ipynb -> (notebook.ipynb, notebook, json)
51 * notebook.json -> (notebook.json, notebook, json)
52 * notebook.py -> (notebook.py, notebook, py)
53 * notebook -> (notebook.ipynb, notebook, json)
54
55 Parameters
56 ----------
57 fname : unicode
58 The notebook filename. The filename can use a specific filename
59 extention (.ipynb, .json, .py) or none, in which case .ipynb will
60 be assumed.
61
62 Returns
63 -------
64 (fname, name, format) : (unicode, unicode, unicode)
65 The filename, notebook name and format.
66 """
67 if fname.endswith(u'.ipynb'):
68 format = u'json'
69 elif fname.endswith(u'.json'):
70 format = u'json'
71 elif fname.endswith(u'.py'):
72 format = u'py'
73 else:
74 fname = fname + u'.ipynb'
75 format = u'json'
76 name = fname.split('.')[0]
77 return fname, name, format
78
@@ -0,0 +1,50 b''
1 """Code for converting notebooks to and from the v2 format.
2
3 Authors:
4
5 * Brian Granger
6 """
7
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
18
19 from .nbbase import (
20 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output
21 )
22
23 #-----------------------------------------------------------------------------
24 # Code
25 #-----------------------------------------------------------------------------
26
27 def convert_to_this_nbformat(nb, orig_version=1):
28 """Convert a notebook to the v2 format.
29
30 Parameters
31 ----------
32 nb : NotebookNode
33 The Python representation of the notebook to convert.
34 orig_version : int
35 The original version of the notebook to convert.
36 """
37 if orig_version == 1:
38 newnb = new_notebook()
39 ws = new_worksheet()
40 for cell in nb.cells:
41 if cell.cell_type == u'code':
42 newcell = new_code_cell(input=cell.get('code'),prompt_number=cell.get('prompt_number'))
43 elif cell.cell_type == u'text':
44 newcell = new_text_cell(u'markdown',source=cell.get('text'))
45 ws.cells.append(newcell)
46 newnb.worksheets.append(ws)
47 return newnb
48 else:
49 raise ValueError('Cannot convert a notebook from v%s to v2' % orig_version)
50
@@ -0,0 +1,179 b''
1 """The basic dict based notebook format.
2
3 The Python representation of a notebook is a nested structure of
4 dictionary subclasses that support attribute access
5 (IPython.utils.ipstruct.Struct). The functions in this module are merely
6 helpers to build the structs in the right form.
7
8 Authors:
9
10 * Brian Granger
11 """
12
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2011 The IPython Development Team
15 #
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
19
20 #-----------------------------------------------------------------------------
21 # Imports
22 #-----------------------------------------------------------------------------
23
24 import pprint
25 import uuid
26
27 from IPython.utils.ipstruct import Struct
28
29 #-----------------------------------------------------------------------------
30 # Code
31 #-----------------------------------------------------------------------------
32
33 class NotebookNode(Struct):
34 pass
35
36
37 def from_dict(d):
38 if isinstance(d, dict):
39 newd = NotebookNode()
40 for k,v in d.items():
41 newd[k] = from_dict(v)
42 return newd
43 elif isinstance(d, (tuple, list)):
44 return [from_dict(i) for i in d]
45 else:
46 return d
47
48
49 def new_output(output_type=None, output_text=None, output_png=None,
50 output_html=None, output_svg=None, output_latex=None, output_json=None,
51 output_javascript=None, output_jpeg=None, prompt_number=None,
52 etype=None, evalue=None, traceback=None):
53 """Create a new code cell with input and output"""
54 output = NotebookNode()
55 if output_type is not None:
56 output.output_type = unicode(output_type)
57
58 if output_type != 'pyerr':
59 if output_text is not None:
60 output.text = unicode(output_text)
61 if output_png is not None:
62 output.png = bytes(output_png)
63 if output_jpeg is not None:
64 output.jpeg = bytes(output_jpeg)
65 if output_html is not None:
66 output.html = unicode(output_html)
67 if output_svg is not None:
68 output.svg = unicode(output_svg)
69 if output_latex is not None:
70 output.latex = unicode(output_latex)
71 if output_json is not None:
72 output.json = unicode(output_json)
73 if output_javascript is not None:
74 output.javascript = unicode(output_javascript)
75
76 if output_type == u'pyout':
77 if prompt_number is not None:
78 output.prompt_number = int(prompt_number)
79
80 if output_type == u'pyerr':
81 if etype is not None:
82 output.etype = unicode(etype)
83 if evalue is not None:
84 output.evalue = unicode(evalue)
85 if traceback is not None:
86 output.traceback = [unicode(frame) for frame in list(traceback)]
87
88 return output
89
90
91 def new_code_cell(input=None, prompt_number=None, outputs=None,
92 language=u'python', collapsed=False):
93 """Create a new code cell with input and output"""
94 cell = NotebookNode()
95 cell.cell_type = u'code'
96 if language is not None:
97 cell.language = unicode(language)
98 if input is not None:
99 cell.input = unicode(input)
100 if prompt_number is not None:
101 cell.prompt_number = int(prompt_number)
102 if outputs is None:
103 cell.outputs = []
104 else:
105 cell.outputs = outputs
106 if collapsed is not None:
107 cell.collapsed = bool(collapsed)
108
109 return cell
110
111 def new_text_cell(cell_type, source=None, rendered=None):
112 """Create a new text cell."""
113 cell = NotebookNode()
114 if source is not None:
115 cell.source = unicode(source)
116 if rendered is not None:
117 cell.rendered = unicode(rendered)
118 cell.cell_type = cell_type
119 return cell
120
121
122 def new_worksheet(name=None, cells=None):
123 """Create a worksheet by name with with a list of cells."""
124 ws = NotebookNode()
125 if name is not None:
126 ws.name = unicode(name)
127 if cells is None:
128 ws.cells = []
129 else:
130 ws.cells = list(cells)
131 return ws
132
133
134 def new_notebook(metadata=None, worksheets=None):
135 """Create a notebook by name, id and a list of worksheets."""
136 nb = NotebookNode()
137 nb.nbformat = 2
138 if worksheets is None:
139 nb.worksheets = []
140 else:
141 nb.worksheets = list(worksheets)
142 if metadata is None:
143 nb.metadata = new_metadata()
144 else:
145 nb.metadata = NotebookNode(metadata)
146 return nb
147
148
149 def new_metadata(name=None, authors=None, license=None, created=None,
150 modified=None, gistid=None):
151 """Create a new metadata node."""
152 metadata = NotebookNode()
153 if name is not None:
154 metadata.name = unicode(name)
155 if authors is not None:
156 metadata.authors = list(authors)
157 if created is not None:
158 metadata.created = unicode(created)
159 if modified is not None:
160 metadata.modified = unicode(modified)
161 if license is not None:
162 metadata.license = unicode(license)
163 if gistid is not None:
164 metadata.gistid = unicode(gistid)
165 return metadata
166
167 def new_author(name=None, email=None, affiliation=None, url=None):
168 """Create a new author."""
169 author = NotebookNode()
170 if name is not None:
171 author.name = unicode(name)
172 if email is not None:
173 author.email = unicode(email)
174 if affiliation is not None:
175 author.affiliation = unicode(affiliation)
176 if url is not None:
177 author.url = unicode(url)
178 return author
179
@@ -0,0 +1,69 b''
1 """Read and write notebooks in JSON format.
2
3 Authors:
4
5 * Brian Granger
6 """
7
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
18
19 import copy
20 import json
21
22 from .nbbase import from_dict
23 from .rwbase import (
24 NotebookReader, NotebookWriter, restore_bytes, rejoin_lines, split_lines
25 )
26
27 #-----------------------------------------------------------------------------
28 # Code
29 #-----------------------------------------------------------------------------
30
31 class BytesEncoder(json.JSONEncoder):
32 """A JSON encoder that accepts b64 (and other *ascii*) bytestrings."""
33 def default(self, obj):
34 if isinstance(obj, bytes):
35 return obj.decode('ascii')
36 return json.JSONEncoder.default(self, obj)
37
38
39 class JSONReader(NotebookReader):
40
41 def reads(self, s, **kwargs):
42 nb = json.loads(s, **kwargs)
43 nb = self.to_notebook(nb, **kwargs)
44 return nb
45
46 def to_notebook(self, d, **kwargs):
47 return restore_bytes(rejoin_lines(from_dict(d)))
48
49
50 class JSONWriter(NotebookWriter):
51
52 def writes(self, nb, **kwargs):
53 kwargs['cls'] = BytesEncoder
54 kwargs['indent'] = 1
55 kwargs['sort_keys'] = True
56 if kwargs.pop('split_lines', True):
57 nb = split_lines(copy.deepcopy(nb))
58 return json.dumps(nb, **kwargs)
59
60
61 _reader = JSONReader()
62 _writer = JSONWriter()
63
64 reads = _reader.reads
65 read = _reader.read
66 to_notebook = _reader.to_notebook
67 write = _writer.write
68 writes = _writer.writes
69
@@ -0,0 +1,150 b''
1 """Read and write notebooks as regular .py files.
2
3 Authors:
4
5 * Brian Granger
6 """
7
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
18
19 import re
20 from .rwbase import NotebookReader, NotebookWriter
21 from .nbbase import new_code_cell, new_text_cell, new_worksheet, new_notebook
22
23 #-----------------------------------------------------------------------------
24 # Code
25 #-----------------------------------------------------------------------------
26
27 _encoding_declaration_re = re.compile(r"^#.*coding[:=]\s*([-\w.]+)")
28
29 class PyReaderError(Exception):
30 pass
31
32
33 class PyReader(NotebookReader):
34
35 def reads(self, s, **kwargs):
36 return self.to_notebook(s,**kwargs)
37
38 def to_notebook(self, s, **kwargs):
39 lines = s.splitlines()
40 cells = []
41 cell_lines = []
42 state = u'codecell'
43 for line in lines:
44 if line.startswith(u'# <nbformat>') or _encoding_declaration_re.match(line):
45 pass
46 elif line.startswith(u'# <codecell>'):
47 cell = self.new_cell(state, cell_lines)
48 if cell is not None:
49 cells.append(cell)
50 state = u'codecell'
51 cell_lines = []
52 elif line.startswith(u'# <htmlcell>'):
53 cell = self.new_cell(state, cell_lines)
54 if cell is not None:
55 cells.append(cell)
56 state = u'htmlcell'
57 cell_lines = []
58 elif line.startswith(u'# <markdowncell>'):
59 cell = self.new_cell(state, cell_lines)
60 if cell is not None:
61 cells.append(cell)
62 state = u'markdowncell'
63 cell_lines = []
64 else:
65 cell_lines.append(line)
66 if cell_lines and state == u'codecell':
67 cell = self.new_cell(state, cell_lines)
68 if cell is not None:
69 cells.append(cell)
70 ws = new_worksheet(cells=cells)
71 nb = new_notebook(worksheets=[ws])
72 return nb
73
74 def new_cell(self, state, lines):
75 if state == u'codecell':
76 input = u'\n'.join(lines)
77 input = input.strip(u'\n')
78 if input:
79 return new_code_cell(input=input)
80 elif state == u'htmlcell':
81 text = self._remove_comments(lines)
82 if text:
83 return new_text_cell(u'html',source=text)
84 elif state == u'markdowncell':
85 text = self._remove_comments(lines)
86 if text:
87 return new_text_cell(u'markdown',source=text)
88
89 def _remove_comments(self, lines):
90 new_lines = []
91 for line in lines:
92 if line.startswith(u'#'):
93 new_lines.append(line[2:])
94 else:
95 new_lines.append(line)
96 text = u'\n'.join(new_lines)
97 text = text.strip(u'\n')
98 return text
99
100 def split_lines_into_blocks(self, lines):
101 if len(lines) == 1:
102 yield lines[0]
103 raise StopIteration()
104 import ast
105 source = '\n'.join(lines)
106 code = ast.parse(source)
107 starts = [x.lineno-1 for x in code.body]
108 for i in range(len(starts)-1):
109 yield '\n'.join(lines[starts[i]:starts[i+1]]).strip('\n')
110 yield '\n'.join(lines[starts[-1]:]).strip('\n')
111
112
113 class PyWriter(NotebookWriter):
114
115 def writes(self, nb, **kwargs):
116 lines = [u'# -*- coding: utf-8 -*-']
117 lines.extend([u'# <nbformat>2</nbformat>',''])
118 for ws in nb.worksheets:
119 for cell in ws.cells:
120 if cell.cell_type == u'code':
121 input = cell.get(u'input')
122 if input is not None:
123 lines.extend([u'# <codecell>',u''])
124 lines.extend(input.splitlines())
125 lines.append(u'')
126 elif cell.cell_type == u'html':
127 input = cell.get(u'source')
128 if input is not None:
129 lines.extend([u'# <htmlcell>',u''])
130 lines.extend([u'# ' + line for line in input.splitlines()])
131 lines.append(u'')
132 elif cell.cell_type == u'markdown':
133 input = cell.get(u'source')
134 if input is not None:
135 lines.extend([u'# <markdowncell>',u''])
136 lines.extend([u'# ' + line for line in input.splitlines()])
137 lines.append(u'')
138 lines.append('')
139 return unicode('\n'.join(lines))
140
141
142 _reader = PyReader()
143 _writer = PyWriter()
144
145 reads = _reader.reads
146 read = _reader.read
147 to_notebook = _reader.to_notebook
148 write = _writer.write
149 writes = _writer.writes
150
@@ -0,0 +1,188 b''
1 """Read and write notebook files as XML.
2
3 Authors:
4
5 * Brian Granger
6 """
7
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
18
19 from base64 import encodestring, decodestring
20 import warnings
21 from xml.etree import ElementTree as ET
22
23 from .rwbase import NotebookReader, NotebookWriter
24 from .nbbase import (
25 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
26 new_metadata
27 )
28
29 #-----------------------------------------------------------------------------
30 # Code
31 #-----------------------------------------------------------------------------
32
33 def indent(elem, level=0):
34 i = "\n" + level*" "
35 if len(elem):
36 if not elem.text or not elem.text.strip():
37 elem.text = i + " "
38 if not elem.tail or not elem.tail.strip():
39 elem.tail = i
40 for elem in elem:
41 indent(elem, level+1)
42 if not elem.tail or not elem.tail.strip():
43 elem.tail = i
44 else:
45 if level and (not elem.tail or not elem.tail.strip()):
46 elem.tail = i
47
48
49 def _get_text(e, tag):
50 sub_e = e.find(tag)
51 if sub_e is None:
52 return None
53 else:
54 return sub_e.text
55
56
57 def _set_text(nbnode, attr, parent, tag):
58 if attr in nbnode:
59 e = ET.SubElement(parent, tag)
60 e.text = nbnode[attr]
61
62
63 def _get_int(e, tag):
64 sub_e = e.find(tag)
65 if sub_e is None:
66 return None
67 else:
68 return int(sub_e.text)
69
70
71 def _set_int(nbnode, attr, parent, tag):
72 if attr in nbnode:
73 e = ET.SubElement(parent, tag)
74 e.text = unicode(nbnode[attr])
75
76
77 def _get_bool(e, tag):
78 sub_e = e.find(tag)
79 if sub_e is None:
80 return None
81 else:
82 return bool(int(sub_e.text))
83
84
85 def _set_bool(nbnode, attr, parent, tag):
86 if attr in nbnode:
87 e = ET.SubElement(parent, tag)
88 if nbnode[attr]:
89 e.text = u'1'
90 else:
91 e.text = u'0'
92
93
94 def _get_binary(e, tag):
95 sub_e = e.find(tag)
96 if sub_e is None:
97 return None
98 else:
99 return decodestring(sub_e.text)
100
101
102 def _set_binary(nbnode, attr, parent, tag):
103 if attr in nbnode:
104 e = ET.SubElement(parent, tag)
105 e.text = encodestring(nbnode[attr])
106
107
108 class XMLReader(NotebookReader):
109
110 def reads(self, s, **kwargs):
111 root = ET.fromstring(s)
112 return self.to_notebook(root, **kwargs)
113
114 def to_notebook(self, root, **kwargs):
115 warnings.warn('The XML notebook format is no longer supported, '
116 'please convert your notebooks to JSON.', DeprecationWarning)
117 nbname = _get_text(root,u'name')
118 nbauthor = _get_text(root,u'author')
119 nbemail = _get_text(root,u'email')
120 nblicense = _get_text(root,u'license')
121 nbcreated = _get_text(root,u'created')
122 nbsaved = _get_text(root,u'saved')
123
124 worksheets = []
125 for ws_e in root.find(u'worksheets').getiterator(u'worksheet'):
126 wsname = _get_text(ws_e,u'name')
127 cells = []
128 for cell_e in ws_e.find(u'cells').getiterator():
129 if cell_e.tag == u'codecell':
130 input = _get_text(cell_e,u'input')
131 prompt_number = _get_int(cell_e,u'prompt_number')
132 collapsed = _get_bool(cell_e,u'collapsed')
133 language = _get_text(cell_e,u'language')
134 outputs = []
135 for output_e in cell_e.find(u'outputs').getiterator(u'output'):
136 output_type = _get_text(output_e,u'output_type')
137 output_text = _get_text(output_e,u'text')
138 output_png = _get_binary(output_e,u'png')
139 output_jpeg = _get_binary(output_e,u'jpeg')
140 output_svg = _get_text(output_e,u'svg')
141 output_html = _get_text(output_e,u'html')
142 output_latex = _get_text(output_e,u'latex')
143 output_json = _get_text(output_e,u'json')
144 output_javascript = _get_text(output_e,u'javascript')
145
146 out_prompt_number = _get_int(output_e,u'prompt_number')
147 etype = _get_text(output_e,u'etype')
148 evalue = _get_text(output_e,u'evalue')
149 traceback = []
150 traceback_e = output_e.find(u'traceback')
151 if traceback_e is not None:
152 for frame_e in traceback_e.getiterator(u'frame'):
153 traceback.append(frame_e.text)
154 if len(traceback) == 0:
155 traceback = None
156 output = new_output(output_type=output_type,output_png=output_png,
157 output_text=output_text, output_svg=output_svg,
158 output_html=output_html, output_latex=output_latex,
159 output_json=output_json, output_javascript=output_javascript,
160 output_jpeg=output_jpeg, prompt_number=out_prompt_number,
161 etype=etype, evalue=evalue, traceback=traceback
162 )
163 outputs.append(output)
164 cc = new_code_cell(input=input,prompt_number=prompt_number,
165 language=language,outputs=outputs,collapsed=collapsed)
166 cells.append(cc)
167 if cell_e.tag == u'htmlcell':
168 source = _get_text(cell_e,u'source')
169 rendered = _get_text(cell_e,u'rendered')
170 cells.append(new_text_cell(u'html', source=source, rendered=rendered))
171 if cell_e.tag == u'markdowncell':
172 source = _get_text(cell_e,u'source')
173 rendered = _get_text(cell_e,u'rendered')
174 cells.append(new_text_cell(u'markdown', source=source, rendered=rendered))
175 ws = new_worksheet(name=wsname,cells=cells)
176 worksheets.append(ws)
177
178 md = new_metadata(name=nbname)
179 nb = new_notebook(metadata=md,worksheets=worksheets)
180 return nb
181
182
183 _reader = XMLReader()
184
185 reads = _reader.reads
186 read = _reader.read
187 to_notebook = _reader.to_notebook
188
@@ -0,0 +1,165 b''
1 """Base classes and utilities for readers and writers.
2
3 Authors:
4
5 * Brian Granger
6 """
7
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
14
15 #-----------------------------------------------------------------------------
16 # Imports
17 #-----------------------------------------------------------------------------
18
19 from base64 import encodestring, decodestring
20 import pprint
21
22 from IPython.utils.py3compat import str_to_bytes
23
24 #-----------------------------------------------------------------------------
25 # Code
26 #-----------------------------------------------------------------------------
27
28 def restore_bytes(nb):
29 """Restore bytes of image data from unicode-only formats.
30
31 Base64 encoding is handled elsewhere. Bytes objects in the notebook are
32 always b64-encoded. We DO NOT encode/decode around file formats.
33 """
34 for ws in nb.worksheets:
35 for cell in ws.cells:
36 if cell.cell_type == 'code':
37 for output in cell.outputs:
38 if 'png' in output:
39 output.png = str_to_bytes(output.png, 'ascii')
40 if 'jpeg' in output:
41 output.jpeg = str_to_bytes(output.jpeg, 'ascii')
42 return nb
43
44 # output keys that are likely to have multiline values
45 _multiline_outputs = ['text', 'html', 'svg', 'latex', 'javascript', 'json']
46
47 def rejoin_lines(nb):
48 """rejoin multiline text into strings
49
50 For reversing effects of ``split_lines(nb)``.
51
52 This only rejoins lines that have been split, so if text objects were not split
53 they will pass through unchanged.
54
55 Used when reading JSON files that may have been passed through split_lines.
56 """
57 for ws in nb.worksheets:
58 for cell in ws.cells:
59 if cell.cell_type == 'code':
60 if 'input' in cell and isinstance(cell.input, list):
61 cell.input = u'\n'.join(cell.input)
62 for output in cell.outputs:
63 for key in _multiline_outputs:
64 item = output.get(key, None)
65 if isinstance(item, list):
66 output[key] = u'\n'.join(item)
67 else: # text cell
68 for key in ['source', 'rendered']:
69 item = cell.get(key, None)
70 if isinstance(item, list):
71 cell[key] = u'\n'.join(item)
72 return nb
73
74
75 def split_lines(nb):
76 """split likely multiline text into lists of strings
77
78 For file output more friendly to line-based VCS. ``rejoin_lines(nb)`` will
79 reverse the effects of ``split_lines(nb)``.
80
81 Used when writing JSON files.
82 """
83 for ws in nb.worksheets:
84 for cell in ws.cells:
85 if cell.cell_type == 'code':
86 if 'input' in cell and isinstance(cell.input, basestring):
87 cell.input = cell.input.splitlines()
88 for output in cell.outputs:
89 for key in _multiline_outputs:
90 item = output.get(key, None)
91 if isinstance(item, basestring):
92 output[key] = item.splitlines()
93 else: # text cell
94 for key in ['source', 'rendered']:
95 item = cell.get(key, None)
96 if isinstance(item, basestring):
97 cell[key] = item.splitlines()
98 return nb
99
100 # b64 encode/decode are never actually used, because all bytes objects in
101 # the notebook are already b64-encoded, and we don't need/want to double-encode
102
103 def base64_decode(nb):
104 """Restore all bytes objects in the notebook from base64-encoded strings.
105
106 Note: This is never used
107 """
108 for ws in nb.worksheets:
109 for cell in ws.cells:
110 if cell.cell_type == 'code':
111 for output in cell.outputs:
112 if 'png' in output:
113 if isinstance(output.png, unicode):
114 output.png = output.png.encode('ascii')
115 output.png = decodestring(output.png)
116 if 'jpeg' in output:
117 if isinstance(output.jpeg, unicode):
118 output.jpeg = output.jpeg.encode('ascii')
119 output.jpeg = decodestring(output.jpeg)
120 return nb
121
122
123 def base64_encode(nb):
124 """Base64 encode all bytes objects in the notebook.
125
126 These will be b64-encoded unicode strings
127
128 Note: This is never used
129 """
130 for ws in nb.worksheets:
131 for cell in ws.cells:
132 if cell.cell_type == 'code':
133 for output in cell.outputs:
134 if 'png' in output:
135 output.png = encodestring(output.png).decode('ascii')
136 if 'jpeg' in output:
137 output.jpeg = encodestring(output.jpeg).decode('ascii')
138 return nb
139
140
141 class NotebookReader(object):
142 """A class for reading notebooks."""
143
144 def reads(self, s, **kwargs):
145 """Read a notebook from a string."""
146 raise NotImplementedError("loads must be implemented in a subclass")
147
148 def read(self, fp, **kwargs):
149 """Read a notebook from a file like object"""
150 return self.read(fp.read(), **kwargs)
151
152
153 class NotebookWriter(object):
154 """A class for writing notebooks."""
155
156 def writes(self, nb, **kwargs):
157 """Write a notebook to a string."""
158 raise NotImplementedError("loads must be implemented in a subclass")
159
160 def write(self, nb, fp, **kwargs):
161 """Write a notebook to a file like object"""
162 return fp.write(self.writes(nb,**kwargs))
163
164
165
1 NO CONTENT: new file 100644
NO CONTENT: new file 100644
@@ -0,0 +1,109 b''
1 import os
2 from base64 import encodestring
3
4 from ..nbbase import (
5 NotebookNode,
6 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
7 new_metadata, new_author
8 )
9
10 # some random base64-encoded *bytes*
11 png = encodestring(os.urandom(5))
12 jpeg = encodestring(os.urandom(6))
13
14 ws = new_worksheet(name='worksheet1')
15
16 ws.cells.append(new_text_cell(
17 u'html',
18 source='Some NumPy Examples',
19 rendered='Some NumPy Examples'
20 ))
21
22
23 ws.cells.append(new_code_cell(
24 input='import numpy',
25 prompt_number=1,
26 collapsed=False
27 ))
28
29 ws.cells.append(new_text_cell(
30 u'markdown',
31 source='A random array',
32 rendered='A random array'
33 ))
34
35 ws.cells.append(new_code_cell(
36 input='a = numpy.random.rand(100)',
37 prompt_number=2,
38 collapsed=True
39 ))
40
41 ws.cells.append(new_code_cell(
42 input='print a',
43 prompt_number=3,
44 collapsed=False,
45 outputs=[new_output(
46 output_type=u'pyout',
47 output_text=u'<array a>',
48 output_html=u'The HTML rep',
49 output_latex=u'$a$',
50 output_png=png,
51 output_jpeg=jpeg,
52 output_svg=u'<svg>',
53 output_json=u'json data',
54 output_javascript=u'var i=0;',
55 prompt_number=3
56 ),new_output(
57 output_type=u'display_data',
58 output_text=u'<array a>',
59 output_html=u'The HTML rep',
60 output_latex=u'$a$',
61 output_png=png,
62 output_jpeg=jpeg,
63 output_svg=u'<svg>',
64 output_json=u'json data',
65 output_javascript=u'var i=0;'
66 ),new_output(
67 output_type=u'pyerr',
68 etype=u'NameError',
69 evalue=u'NameError was here',
70 traceback=[u'frame 0', u'frame 1', u'frame 2']
71 )]
72 ))
73
74 authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com',
75 affiliation=u'Fox',url=u'http://www.fox.com')]
76 md = new_metadata(name=u'My Notebook',license=u'BSD',created=u'8601_goes_here',
77 modified=u'8601_goes_here',gistid=u'21341231',authors=authors)
78
79 nb0 = new_notebook(
80 worksheets=[ws, new_worksheet(name='worksheet2')],
81 metadata=md
82 )
83
84 nb0_py = """# -*- coding: utf-8 -*-
85 # <nbformat>2</nbformat>
86
87 # <htmlcell>
88
89 # Some NumPy Examples
90
91 # <codecell>
92
93 import numpy
94
95 # <markdowncell>
96
97 # A random array
98
99 # <codecell>
100
101 a = numpy.random.rand(100)
102
103 # <codecell>
104
105 print a
106
107 """
108
109
@@ -0,0 +1,34 b''
1 import pprint
2 from unittest import TestCase
3
4 from ..nbjson import reads, writes
5 from .nbexamples import nb0
6
7
8 class TestJSON(TestCase):
9
10 def test_roundtrip(self):
11 s = writes(nb0)
12 # print
13 # print pprint.pformat(nb0,indent=2)
14 # print
15 # print pprint.pformat(reads(s),indent=2)
16 # print
17 # print s
18 self.assertEquals(reads(s),nb0)
19
20 def test_roundtrip_nosplit(self):
21 """Ensure that multiline blobs are still readable"""
22 # ensures that notebooks written prior to splitlines change
23 # are still readable.
24 s = writes(nb0, split_lines=False)
25 self.assertEquals(reads(s),nb0)
26
27 def test_roundtrip_split(self):
28 """Ensure that splitting multiline blocks is safe"""
29 # This won't differ from test_roundtrip unless the default changes
30 s = writes(nb0, split_lines=True)
31 self.assertEquals(reads(s),nb0)
32
33
34
@@ -0,0 +1,113 b''
1 from unittest import TestCase
2
3 from ..nbbase import (
4 NotebookNode,
5 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
6 new_author, new_metadata
7 )
8
9 class TestCell(TestCase):
10
11 def test_empty_code_cell(self):
12 cc = new_code_cell()
13 self.assertEquals(cc.cell_type,u'code')
14 self.assertEquals(u'input' not in cc, True)
15 self.assertEquals(u'prompt_number' not in cc, True)
16 self.assertEquals(cc.outputs, [])
17 self.assertEquals(cc.collapsed, False)
18
19 def test_code_cell(self):
20 cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True)
21 cc.outputs = [new_output(output_type=u'pyout',
22 output_svg=u'foo',output_text=u'10',prompt_number=0)]
23 self.assertEquals(cc.input, u'a=10')
24 self.assertEquals(cc.prompt_number, 0)
25 self.assertEquals(cc.language, u'python')
26 self.assertEquals(cc.outputs[0].svg, u'foo')
27 self.assertEquals(cc.outputs[0].text, u'10')
28 self.assertEquals(cc.outputs[0].prompt_number, 0)
29 self.assertEquals(cc.collapsed, True)
30
31 def test_pyerr(self):
32 o = new_output(output_type=u'pyerr', etype=u'NameError',
33 evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2']
34 )
35 self.assertEquals(o.output_type, u'pyerr')
36 self.assertEquals(o.etype, u'NameError')
37 self.assertEquals(o.evalue, u'Name not found')
38 self.assertEquals(o.traceback, [u'frame 0', u'frame 1', u'frame 2'])
39
40 def test_empty_html_cell(self):
41 tc = new_text_cell(u'html')
42 self.assertEquals(tc.cell_type, u'html')
43 self.assertEquals(u'source' not in tc, True)
44 self.assertEquals(u'rendered' not in tc, True)
45
46 def test_html_cell(self):
47 tc = new_text_cell(u'html', 'hi', 'hi')
48 self.assertEquals(tc.source, u'hi')
49 self.assertEquals(tc.rendered, u'hi')
50
51 def test_empty_markdown_cell(self):
52 tc = new_text_cell(u'markdown')
53 self.assertEquals(tc.cell_type, u'markdown')
54 self.assertEquals(u'source' not in tc, True)
55 self.assertEquals(u'rendered' not in tc, True)
56
57 def test_markdown_cell(self):
58 tc = new_text_cell(u'markdown', 'hi', 'hi')
59 self.assertEquals(tc.source, u'hi')
60 self.assertEquals(tc.rendered, u'hi')
61
62
63 class TestWorksheet(TestCase):
64
65 def test_empty_worksheet(self):
66 ws = new_worksheet()
67 self.assertEquals(ws.cells,[])
68 self.assertEquals(u'name' not in ws, True)
69
70 def test_worksheet(self):
71 cells = [new_code_cell(), new_text_cell(u'html')]
72 ws = new_worksheet(cells=cells,name=u'foo')
73 self.assertEquals(ws.cells,cells)
74 self.assertEquals(ws.name,u'foo')
75
76 class TestNotebook(TestCase):
77
78 def test_empty_notebook(self):
79 nb = new_notebook()
80 self.assertEquals(nb.worksheets, [])
81 self.assertEquals(nb.metadata, NotebookNode())
82 self.assertEquals(nb.nbformat,2)
83
84 def test_notebook(self):
85 worksheets = [new_worksheet(),new_worksheet()]
86 metadata = new_metadata(name=u'foo')
87 nb = new_notebook(metadata=metadata,worksheets=worksheets)
88 self.assertEquals(nb.metadata.name,u'foo')
89 self.assertEquals(nb.worksheets,worksheets)
90 self.assertEquals(nb.nbformat,2)
91
92 class TestMetadata(TestCase):
93
94 def test_empty_metadata(self):
95 md = new_metadata()
96 self.assertEquals(u'name' not in md, True)
97 self.assertEquals(u'authors' not in md, True)
98 self.assertEquals(u'license' not in md, True)
99 self.assertEquals(u'saved' not in md, True)
100 self.assertEquals(u'modified' not in md, True)
101 self.assertEquals(u'gistid' not in md, True)
102
103 def test_metadata(self):
104 authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com')]
105 md = new_metadata(name=u'foo',license=u'BSD',created=u'today',
106 modified=u'now',gistid=u'21341231',authors=authors)
107 self.assertEquals(md.name, u'foo')
108 self.assertEquals(md.license, u'BSD')
109 self.assertEquals(md.created, u'today')
110 self.assertEquals(md.modified, u'now')
111 self.assertEquals(md.gistid, u'21341231')
112 self.assertEquals(md.authors, authors)
113
@@ -0,0 +1,17 b''
1 from unittest import TestCase
2
3 from ..nbbase import (
4 NotebookNode,
5 new_code_cell, new_text_cell, new_worksheet, new_notebook
6 )
7
8 from ..nbpy import reads, writes
9 from .nbexamples import nb0, nb0_py
10
11
12 class TestPy(TestCase):
13
14 def test_write(self):
15 s = writes(nb0)
16 self.assertEquals(s,nb0_py)
17
General Comments 0
You need to be logged in to leave comments. Login now