##// END OF EJS Templates
Minor changes to heading cell in nbformat.
Brian Granger -
Show More
@@ -1,189 +1,191 b''
1 1 """The basic dict based notebook format.
2 2
3 3 The Python representation of a notebook is a nested structure of
4 4 dictionary subclasses that support attribute access
5 5 (IPython.utils.ipstruct.Struct). The functions in this module are merely
6 6 helpers to build the structs in the right form.
7 7
8 8 Authors:
9 9
10 10 * Brian Granger
11 11 """
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Copyright (C) 2008-2011 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Imports
22 22 #-----------------------------------------------------------------------------
23 23
24 24 import pprint
25 25 import uuid
26 26
27 27 from IPython.utils.ipstruct import Struct
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Code
31 31 #-----------------------------------------------------------------------------
32 32
33 33 class NotebookNode(Struct):
34 34 pass
35 35
36 36
37 37 def from_dict(d):
38 38 if isinstance(d, dict):
39 39 newd = NotebookNode()
40 40 for k,v in d.items():
41 41 newd[k] = from_dict(v)
42 42 return newd
43 43 elif isinstance(d, (tuple, list)):
44 44 return [from_dict(i) for i in d]
45 45 else:
46 46 return d
47 47
48 48
49 49 def new_output(output_type=None, output_text=None, output_png=None,
50 50 output_html=None, output_svg=None, output_latex=None, output_json=None,
51 51 output_javascript=None, output_jpeg=None, prompt_number=None,
52 52 etype=None, evalue=None, traceback=None):
53 53 """Create a new code cell with input and output"""
54 54 output = NotebookNode()
55 55 if output_type is not None:
56 56 output.output_type = unicode(output_type)
57 57
58 58 if output_type != 'pyerr':
59 59 if output_text is not None:
60 60 output.text = unicode(output_text)
61 61 if output_png is not None:
62 62 output.png = bytes(output_png)
63 63 if output_jpeg is not None:
64 64 output.jpeg = bytes(output_jpeg)
65 65 if output_html is not None:
66 66 output.html = unicode(output_html)
67 67 if output_svg is not None:
68 68 output.svg = unicode(output_svg)
69 69 if output_latex is not None:
70 70 output.latex = unicode(output_latex)
71 71 if output_json is not None:
72 72 output.json = unicode(output_json)
73 73 if output_javascript is not None:
74 74 output.javascript = unicode(output_javascript)
75 75
76 76 if output_type == u'pyout':
77 77 if prompt_number is not None:
78 78 output.prompt_number = int(prompt_number)
79 79
80 80 if output_type == u'pyerr':
81 81 if etype is not None:
82 82 output.etype = unicode(etype)
83 83 if evalue is not None:
84 84 output.evalue = unicode(evalue)
85 85 if traceback is not None:
86 86 output.traceback = [unicode(frame) for frame in list(traceback)]
87 87
88 88 return output
89 89
90 90
91 91 def new_code_cell(input=None, prompt_number=None, outputs=None,
92 92 language=u'python', collapsed=False):
93 93 """Create a new code cell with input and output"""
94 94 cell = NotebookNode()
95 95 cell.cell_type = u'code'
96 96 if language is not None:
97 97 cell.language = unicode(language)
98 98 if input is not None:
99 99 cell.input = unicode(input)
100 100 if prompt_number is not None:
101 101 cell.prompt_number = int(prompt_number)
102 102 if outputs is None:
103 103 cell.outputs = []
104 104 else:
105 105 cell.outputs = outputs
106 106 if collapsed is not None:
107 107 cell.collapsed = bool(collapsed)
108 108
109 109 return cell
110 110
111 111 def new_text_cell(cell_type, source=None, rendered=None):
112 112 """Create a new text cell."""
113 113 cell = NotebookNode()
114 114 if source is not None:
115 115 cell.source = unicode(source)
116 116 if rendered is not None:
117 117 cell.rendered = unicode(rendered)
118 118 cell.cell_type = cell_type
119 119 return cell
120 120
121 121
122 def new_heading_cell(source=None, level=1):
122 def new_heading_cell(source=None, rendered=None, level=1):
123 123 """Create a new section cell with a given integer level."""
124 124 cell = NotebookNode()
125 125 cell.cell_type = u'heading'
126 126 if source is not None:
127 127 cell.source = unicode(source)
128 if rendered is not None:
129 cell.rendered = unicode(rendered)
128 130 cell.level = int(level)
129 131 return cell
130 132
131 133
132 134 def new_worksheet(name=None, cells=None):
133 135 """Create a worksheet by name with with a list of cells."""
134 136 ws = NotebookNode()
135 137 if name is not None:
136 138 ws.name = unicode(name)
137 139 if cells is None:
138 140 ws.cells = []
139 141 else:
140 142 ws.cells = list(cells)
141 143 return ws
142 144
143 145
144 146 def new_notebook(metadata=None, worksheets=None):
145 147 """Create a notebook by name, id and a list of worksheets."""
146 148 nb = NotebookNode()
147 149 nb.nbformat = 2
148 150 if worksheets is None:
149 151 nb.worksheets = []
150 152 else:
151 153 nb.worksheets = list(worksheets)
152 154 if metadata is None:
153 155 nb.metadata = new_metadata()
154 156 else:
155 157 nb.metadata = NotebookNode(metadata)
156 158 return nb
157 159
158 160
159 161 def new_metadata(name=None, authors=None, license=None, created=None,
160 162 modified=None, gistid=None):
161 163 """Create a new metadata node."""
162 164 metadata = NotebookNode()
163 165 if name is not None:
164 166 metadata.name = unicode(name)
165 167 if authors is not None:
166 168 metadata.authors = list(authors)
167 169 if created is not None:
168 170 metadata.created = unicode(created)
169 171 if modified is not None:
170 172 metadata.modified = unicode(modified)
171 173 if license is not None:
172 174 metadata.license = unicode(license)
173 175 if gistid is not None:
174 176 metadata.gistid = unicode(gistid)
175 177 return metadata
176 178
177 179 def new_author(name=None, email=None, affiliation=None, url=None):
178 180 """Create a new author."""
179 181 author = NotebookNode()
180 182 if name is not None:
181 183 author.name = unicode(name)
182 184 if email is not None:
183 185 author.email = unicode(email)
184 186 if affiliation is not None:
185 187 author.affiliation = unicode(affiliation)
186 188 if url is not None:
187 189 author.url = unicode(url)
188 190 return author
189 191
@@ -1,169 +1,165 b''
1 1 """Base classes and utilities for readers and writers.
2 2
3 3 Authors:
4 4
5 5 * Brian Granger
6 6 """
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2008-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from base64 import encodestring, decodestring
20 20 import pprint
21 21
22 22 from IPython.utils.py3compat import str_to_bytes
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Code
26 26 #-----------------------------------------------------------------------------
27 27
28 28 def restore_bytes(nb):
29 29 """Restore bytes of image data from unicode-only formats.
30 30
31 31 Base64 encoding is handled elsewhere. Bytes objects in the notebook are
32 32 always b64-encoded. We DO NOT encode/decode around file formats.
33 33 """
34 34 for ws in nb.worksheets:
35 35 for cell in ws.cells:
36 36 if cell.cell_type == 'code':
37 37 for output in cell.outputs:
38 38 if 'png' in output:
39 39 output.png = str_to_bytes(output.png, 'ascii')
40 40 if 'jpeg' in output:
41 41 output.jpeg = str_to_bytes(output.jpeg, 'ascii')
42 42 return nb
43 43
44 44 # output keys that are likely to have multiline values
45 45 _multiline_outputs = ['text', 'html', 'svg', 'latex', 'javascript', 'json']
46 46
47 47 def rejoin_lines(nb):
48 48 """rejoin multiline text into strings
49 49
50 50 For reversing effects of ``split_lines(nb)``.
51 51
52 52 This only rejoins lines that have been split, so if text objects were not split
53 53 they will pass through unchanged.
54 54
55 55 Used when reading JSON files that may have been passed through split_lines.
56 56 """
57 57 for ws in nb.worksheets:
58 58 for cell in ws.cells:
59 59 if cell.cell_type == 'code':
60 60 if 'input' in cell and isinstance(cell.input, list):
61 61 cell.input = u'\n'.join(cell.input)
62 62 for output in cell.outputs:
63 63 for key in _multiline_outputs:
64 64 item = output.get(key, None)
65 65 if isinstance(item, list):
66 66 output[key] = u'\n'.join(item)
67 elif cell.cell_type == 'heading':
68 pass
69 else: # text cell
67 else: # text, heading cell
70 68 for key in ['source', 'rendered']:
71 69 item = cell.get(key, None)
72 70 if isinstance(item, list):
73 71 cell[key] = u'\n'.join(item)
74 72 return nb
75 73
76 74
77 75 def split_lines(nb):
78 76 """split likely multiline text into lists of strings
79 77
80 78 For file output more friendly to line-based VCS. ``rejoin_lines(nb)`` will
81 79 reverse the effects of ``split_lines(nb)``.
82 80
83 81 Used when writing JSON files.
84 82 """
85 83 for ws in nb.worksheets:
86 84 for cell in ws.cells:
87 85 if cell.cell_type == 'code':
88 86 if 'input' in cell and isinstance(cell.input, basestring):
89 87 cell.input = cell.input.splitlines()
90 88 for output in cell.outputs:
91 89 for key in _multiline_outputs:
92 90 item = output.get(key, None)
93 91 if isinstance(item, basestring):
94 92 output[key] = item.splitlines()
95 elif cell.cell_type == 'heading':
96 pass
97 else: # text cell
93 else: # text, heading cell
98 94 for key in ['source', 'rendered']:
99 95 item = cell.get(key, None)
100 96 if isinstance(item, basestring):
101 97 cell[key] = item.splitlines()
102 98 return nb
103 99
104 100 # b64 encode/decode are never actually used, because all bytes objects in
105 101 # the notebook are already b64-encoded, and we don't need/want to double-encode
106 102
107 103 def base64_decode(nb):
108 104 """Restore all bytes objects in the notebook from base64-encoded strings.
109 105
110 106 Note: This is never used
111 107 """
112 108 for ws in nb.worksheets:
113 109 for cell in ws.cells:
114 110 if cell.cell_type == 'code':
115 111 for output in cell.outputs:
116 112 if 'png' in output:
117 113 if isinstance(output.png, unicode):
118 114 output.png = output.png.encode('ascii')
119 115 output.png = decodestring(output.png)
120 116 if 'jpeg' in output:
121 117 if isinstance(output.jpeg, unicode):
122 118 output.jpeg = output.jpeg.encode('ascii')
123 119 output.jpeg = decodestring(output.jpeg)
124 120 return nb
125 121
126 122
127 123 def base64_encode(nb):
128 124 """Base64 encode all bytes objects in the notebook.
129 125
130 126 These will be b64-encoded unicode strings
131 127
132 128 Note: This is never used
133 129 """
134 130 for ws in nb.worksheets:
135 131 for cell in ws.cells:
136 132 if cell.cell_type == 'code':
137 133 for output in cell.outputs:
138 134 if 'png' in output:
139 135 output.png = encodestring(output.png).decode('ascii')
140 136 if 'jpeg' in output:
141 137 output.jpeg = encodestring(output.jpeg).decode('ascii')
142 138 return nb
143 139
144 140
145 141 class NotebookReader(object):
146 142 """A class for reading notebooks."""
147 143
148 144 def reads(self, s, **kwargs):
149 145 """Read a notebook from a string."""
150 146 raise NotImplementedError("loads must be implemented in a subclass")
151 147
152 148 def read(self, fp, **kwargs):
153 149 """Read a notebook from a file like object"""
154 150 return self.read(fp.read(), **kwargs)
155 151
156 152
157 153 class NotebookWriter(object):
158 154 """A class for writing notebooks."""
159 155
160 156 def writes(self, nb, **kwargs):
161 157 """Write a notebook to a string."""
162 158 raise NotImplementedError("loads must be implemented in a subclass")
163 159
164 160 def write(self, nb, fp, **kwargs):
165 161 """Write a notebook to a file like object"""
166 162 return fp.write(self.writes(nb,**kwargs))
167 163
168 164
169 165
@@ -1,134 +1,136 b''
1 1 from unittest import TestCase
2 2
3 3 from ..nbbase import (
4 4 NotebookNode,
5 5 new_code_cell, new_text_cell, new_worksheet, new_notebook, new_output,
6 6 new_author, new_metadata, new_heading_cell
7 7 )
8 8
9 9 class TestCell(TestCase):
10 10
11 11 def test_empty_code_cell(self):
12 12 cc = new_code_cell()
13 13 self.assertEquals(cc.cell_type,u'code')
14 14 self.assertEquals(u'input' not in cc, True)
15 15 self.assertEquals(u'prompt_number' not in cc, True)
16 16 self.assertEquals(cc.outputs, [])
17 17 self.assertEquals(cc.collapsed, False)
18 18
19 19 def test_code_cell(self):
20 20 cc = new_code_cell(input='a=10', prompt_number=0, collapsed=True)
21 21 cc.outputs = [new_output(output_type=u'pyout',
22 22 output_svg=u'foo',output_text=u'10',prompt_number=0)]
23 23 self.assertEquals(cc.input, u'a=10')
24 24 self.assertEquals(cc.prompt_number, 0)
25 25 self.assertEquals(cc.language, u'python')
26 26 self.assertEquals(cc.outputs[0].svg, u'foo')
27 27 self.assertEquals(cc.outputs[0].text, u'10')
28 28 self.assertEquals(cc.outputs[0].prompt_number, 0)
29 29 self.assertEquals(cc.collapsed, True)
30 30
31 31 def test_pyerr(self):
32 32 o = new_output(output_type=u'pyerr', etype=u'NameError',
33 33 evalue=u'Name not found', traceback=[u'frame 0', u'frame 1', u'frame 2']
34 34 )
35 35 self.assertEquals(o.output_type, u'pyerr')
36 36 self.assertEquals(o.etype, u'NameError')
37 37 self.assertEquals(o.evalue, u'Name not found')
38 38 self.assertEquals(o.traceback, [u'frame 0', u'frame 1', u'frame 2'])
39 39
40 40 def test_empty_html_cell(self):
41 41 tc = new_text_cell(u'html')
42 42 self.assertEquals(tc.cell_type, u'html')
43 43 self.assertEquals(u'source' not in tc, True)
44 44 self.assertEquals(u'rendered' not in tc, True)
45 45
46 46 def test_html_cell(self):
47 47 tc = new_text_cell(u'html', 'hi', 'hi')
48 48 self.assertEquals(tc.source, u'hi')
49 49 self.assertEquals(tc.rendered, u'hi')
50 50
51 51 def test_empty_markdown_cell(self):
52 52 tc = new_text_cell(u'markdown')
53 53 self.assertEquals(tc.cell_type, u'markdown')
54 54 self.assertEquals(u'source' not in tc, True)
55 55 self.assertEquals(u'rendered' not in tc, True)
56 56
57 57 def test_markdown_cell(self):
58 58 tc = new_text_cell(u'markdown', 'hi', 'hi')
59 59 self.assertEquals(tc.source, u'hi')
60 60 self.assertEquals(tc.rendered, u'hi')
61 61
62 62 def test_empty_rst_cell(self):
63 63 tc = new_text_cell(u'rst')
64 64 self.assertEquals(tc.cell_type, u'rst')
65 65 self.assertEquals(u'source' not in tc, True)
66 66 self.assertEquals(u'rendered' not in tc, True)
67 67
68 68 def test_rst_cell(self):
69 69 tc = new_text_cell(u'rst', 'hi', 'hi')
70 70 self.assertEquals(tc.source, u'hi')
71 71 self.assertEquals(tc.rendered, u'hi')
72 72
73 73 def test_empty_heading_cell(self):
74 74 tc = new_heading_cell()
75 75 self.assertEquals(tc.cell_type, u'heading')
76 76 self.assertEquals(u'source' not in tc, True)
77 self.assertEquals(u'rendered' not in tc, True)
77 78
78 79 def test_heading_cell(self):
79 tc = new_heading_cell(u'My Heading', level=2)
80 self.assertEquals(tc.source, u'My Heading')
80 tc = new_heading_cell(u'hi', u'hi', level=2)
81 self.assertEquals(tc.source, u'hi')
82 self.assertEquals(tc.rendered, u'hi')
81 83 self.assertEquals(tc.level, 2)
82 84
83 85
84 86 class TestWorksheet(TestCase):
85 87
86 88 def test_empty_worksheet(self):
87 89 ws = new_worksheet()
88 90 self.assertEquals(ws.cells,[])
89 91 self.assertEquals(u'name' not in ws, True)
90 92
91 93 def test_worksheet(self):
92 94 cells = [new_code_cell(), new_text_cell(u'html')]
93 95 ws = new_worksheet(cells=cells,name=u'foo')
94 96 self.assertEquals(ws.cells,cells)
95 97 self.assertEquals(ws.name,u'foo')
96 98
97 99 class TestNotebook(TestCase):
98 100
99 101 def test_empty_notebook(self):
100 102 nb = new_notebook()
101 103 self.assertEquals(nb.worksheets, [])
102 104 self.assertEquals(nb.metadata, NotebookNode())
103 105 self.assertEquals(nb.nbformat,2)
104 106
105 107 def test_notebook(self):
106 108 worksheets = [new_worksheet(),new_worksheet()]
107 109 metadata = new_metadata(name=u'foo')
108 110 nb = new_notebook(metadata=metadata,worksheets=worksheets)
109 111 self.assertEquals(nb.metadata.name,u'foo')
110 112 self.assertEquals(nb.worksheets,worksheets)
111 113 self.assertEquals(nb.nbformat,2)
112 114
113 115 class TestMetadata(TestCase):
114 116
115 117 def test_empty_metadata(self):
116 118 md = new_metadata()
117 119 self.assertEquals(u'name' not in md, True)
118 120 self.assertEquals(u'authors' not in md, True)
119 121 self.assertEquals(u'license' not in md, True)
120 122 self.assertEquals(u'saved' not in md, True)
121 123 self.assertEquals(u'modified' not in md, True)
122 124 self.assertEquals(u'gistid' not in md, True)
123 125
124 126 def test_metadata(self):
125 127 authors = [new_author(name='Bart Simpson',email='bsimpson@fox.com')]
126 128 md = new_metadata(name=u'foo',license=u'BSD',created=u'today',
127 129 modified=u'now',gistid=u'21341231',authors=authors)
128 130 self.assertEquals(md.name, u'foo')
129 131 self.assertEquals(md.license, u'BSD')
130 132 self.assertEquals(md.created, u'today')
131 133 self.assertEquals(md.modified, u'now')
132 134 self.assertEquals(md.gistid, u'21341231')
133 135 self.assertEquals(md.authors, authors)
134 136
General Comments 0
You need to be logged in to leave comments. Login now