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