##// END OF EJS Templates
use cast_unicode in nbformat
MinRK -
Show More
@@ -1,215 +1,216 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 from IPython.utils.py3compat import cast_unicode
28 29
29 30 #-----------------------------------------------------------------------------
30 31 # Code
31 32 #-----------------------------------------------------------------------------
32 33
33 34 # Change this when incrementing the nbformat version
34 35 nbformat = 3
35 36 nbformat_minor = 0
36 37
37 38 class NotebookNode(Struct):
38 39 pass
39 40
40 41
41 42 def from_dict(d):
42 43 if isinstance(d, dict):
43 44 newd = NotebookNode()
44 45 for k,v in d.items():
45 46 newd[k] = from_dict(v)
46 47 return newd
47 48 elif isinstance(d, (tuple, list)):
48 49 return [from_dict(i) for i in d]
49 50 else:
50 51 return d
51 52
52 53
53 54 def new_output(output_type=None, output_text=None, output_png=None,
54 55 output_html=None, output_svg=None, output_latex=None, output_json=None,
55 56 output_javascript=None, output_jpeg=None, prompt_number=None,
56 57 ename=None, evalue=None, traceback=None, stream=None, metadata=None):
57 58 """Create a new code cell with input and output"""
58 59 output = NotebookNode()
59 60 if output_type is not None:
60 61 output.output_type = unicode(output_type)
61 62
62 63 if metadata is None:
63 64 metadata = {}
64 65 if not isinstance(metadata, dict):
65 66 raise TypeError("metadata must be dict")
66 67 output.metadata = metadata
67 68
68 69 if output_type != 'pyerr':
69 70 if output_text is not None:
70 output.text = unicode(output_text)
71 output.text = cast_unicode(output_text)
71 72 if output_png is not None:
72 output.png = unicode(output_png)
73 output.png = cast_unicode(output_png)
73 74 if output_jpeg is not None:
74 output.jpeg = unicode(output_jpeg)
75 output.jpeg = cast_unicode(output_jpeg)
75 76 if output_html is not None:
76 output.html = unicode(output_html)
77 output.html = cast_unicode(output_html)
77 78 if output_svg is not None:
78 output.svg = unicode(output_svg)
79 output.svg = cast_unicode(output_svg)
79 80 if output_latex is not None:
80 output.latex = unicode(output_latex)
81 output.latex = cast_unicode(output_latex)
81 82 if output_json is not None:
82 output.json = unicode(output_json)
83 output.json = cast_unicode(output_json)
83 84 if output_javascript is not None:
84 output.javascript = unicode(output_javascript)
85 output.javascript = cast_unicode(output_javascript)
85 86
86 87 if output_type == u'pyout':
87 88 if prompt_number is not None:
88 89 output.prompt_number = int(prompt_number)
89 90
90 91 if output_type == u'pyerr':
91 92 if ename is not None:
92 output.ename = unicode(ename)
93 output.ename = cast_unicode(ename)
93 94 if evalue is not None:
94 output.evalue = unicode(evalue)
95 output.evalue = cast_unicode(evalue)
95 96 if traceback is not None:
96 output.traceback = [unicode(frame) for frame in list(traceback)]
97 output.traceback = [cast_unicode(frame) for frame in list(traceback)]
97 98
98 99 if output_type == u'stream':
99 output.stream = 'stdout' if stream is None else unicode(stream)
100 output.stream = 'stdout' if stream is None else cast_unicode(stream)
100 101
101 102 return output
102 103
103 104
104 105 def new_code_cell(input=None, prompt_number=None, outputs=None,
105 106 language=u'python', collapsed=False, metadata=None):
106 107 """Create a new code cell with input and output"""
107 108 cell = NotebookNode()
108 109 cell.cell_type = u'code'
109 110 if language is not None:
110 cell.language = unicode(language)
111 cell.language = cast_unicode(language)
111 112 if input is not None:
112 cell.input = unicode(input)
113 cell.input = cast_unicode(input)
113 114 if prompt_number is not None:
114 115 cell.prompt_number = int(prompt_number)
115 116 if outputs is None:
116 117 cell.outputs = []
117 118 else:
118 119 cell.outputs = outputs
119 120 if collapsed is not None:
120 121 cell.collapsed = bool(collapsed)
121 122 cell.metadata = NotebookNode(metadata or {})
122 123
123 124 return cell
124 125
125 126 def new_text_cell(cell_type, source=None, rendered=None, metadata=None):
126 127 """Create a new text cell."""
127 128 cell = NotebookNode()
128 129 # VERSIONHACK: plaintext -> raw
129 130 # handle never-released plaintext name for raw cells
130 131 if cell_type == 'plaintext':
131 132 cell_type = 'raw'
132 133 if source is not None:
133 cell.source = unicode(source)
134 cell.source = cast_unicode(source)
134 135 if rendered is not None:
135 cell.rendered = unicode(rendered)
136 cell.rendered = cast_unicode(rendered)
136 137 cell.metadata = NotebookNode(metadata or {})
137 138 cell.cell_type = cell_type
138 139 return cell
139 140
140 141
141 142 def new_heading_cell(source=None, rendered=None, level=1, metadata=None):
142 143 """Create a new section cell with a given integer level."""
143 144 cell = NotebookNode()
144 145 cell.cell_type = u'heading'
145 146 if source is not None:
146 cell.source = unicode(source)
147 cell.source = cast_unicode(source)
147 148 if rendered is not None:
148 cell.rendered = unicode(rendered)
149 cell.rendered = cast_unicode(rendered)
149 150 cell.level = int(level)
150 151 cell.metadata = NotebookNode(metadata or {})
151 152 return cell
152 153
153 154
154 155 def new_worksheet(name=None, cells=None, metadata=None):
155 156 """Create a worksheet by name with with a list of cells."""
156 157 ws = NotebookNode()
157 158 if name is not None:
158 ws.name = unicode(name)
159 ws.name = cast_unicode(name)
159 160 if cells is None:
160 161 ws.cells = []
161 162 else:
162 163 ws.cells = list(cells)
163 164 ws.metadata = NotebookNode(metadata or {})
164 165 return ws
165 166
166 167
167 168 def new_notebook(name=None, metadata=None, worksheets=None):
168 169 """Create a notebook by name, id and a list of worksheets."""
169 170 nb = NotebookNode()
170 171 nb.nbformat = nbformat
171 172 nb.nbformat_minor = nbformat_minor
172 173 if worksheets is None:
173 174 nb.worksheets = []
174 175 else:
175 176 nb.worksheets = list(worksheets)
176 177 if metadata is None:
177 178 nb.metadata = new_metadata()
178 179 else:
179 180 nb.metadata = NotebookNode(metadata)
180 181 if name is not None:
181 nb.metadata.name = unicode(name)
182 nb.metadata.name = cast_unicode(name)
182 183 return nb
183 184
184 185
185 186 def new_metadata(name=None, authors=None, license=None, created=None,
186 187 modified=None, gistid=None):
187 188 """Create a new metadata node."""
188 189 metadata = NotebookNode()
189 190 if name is not None:
190 metadata.name = unicode(name)
191 metadata.name = cast_unicode(name)
191 192 if authors is not None:
192 193 metadata.authors = list(authors)
193 194 if created is not None:
194 metadata.created = unicode(created)
195 metadata.created = cast_unicode(created)
195 196 if modified is not None:
196 metadata.modified = unicode(modified)
197 metadata.modified = cast_unicode(modified)
197 198 if license is not None:
198 metadata.license = unicode(license)
199 metadata.license = cast_unicode(license)
199 200 if gistid is not None:
200 metadata.gistid = unicode(gistid)
201 metadata.gistid = cast_unicode(gistid)
201 202 return metadata
202 203
203 204 def new_author(name=None, email=None, affiliation=None, url=None):
204 205 """Create a new author."""
205 206 author = NotebookNode()
206 207 if name is not None:
207 author.name = unicode(name)
208 author.name = cast_unicode(name)
208 209 if email is not None:
209 author.email = unicode(email)
210 author.email = cast_unicode(email)
210 211 if affiliation is not None:
211 author.affiliation = unicode(affiliation)
212 author.affiliation = cast_unicode(affiliation)
212 213 if url is not None:
213 author.url = unicode(url)
214 author.url = cast_unicode(url)
214 215 return author
215 216
@@ -1,204 +1,204 b''
1 1 """Read and write notebooks as regular .py files.
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 import re
20 20 from .rwbase import NotebookReader, NotebookWriter
21 21 from .nbbase import (
22 22 new_code_cell, new_text_cell, new_worksheet,
23 23 new_notebook, new_heading_cell, nbformat, nbformat_minor,
24 24 )
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Code
28 28 #-----------------------------------------------------------------------------
29 29
30 30 _encoding_declaration_re = re.compile(r"^#.*coding[:=]\s*([-\w.]+)")
31 31
32 32 class PyReaderError(Exception):
33 33 pass
34 34
35 35
36 36 class PyReader(NotebookReader):
37 37
38 38 def reads(self, s, **kwargs):
39 39 return self.to_notebook(s,**kwargs)
40 40
41 41 def to_notebook(self, s, **kwargs):
42 42 lines = s.splitlines()
43 43 cells = []
44 44 cell_lines = []
45 45 kwargs = {}
46 46 state = u'codecell'
47 47 for line in lines:
48 48 if line.startswith(u'# <nbformat>') or _encoding_declaration_re.match(line):
49 49 pass
50 50 elif line.startswith(u'# <codecell>'):
51 51 cell = self.new_cell(state, cell_lines, **kwargs)
52 52 if cell is not None:
53 53 cells.append(cell)
54 54 state = u'codecell'
55 55 cell_lines = []
56 56 kwargs = {}
57 57 elif line.startswith(u'# <htmlcell>'):
58 58 cell = self.new_cell(state, cell_lines, **kwargs)
59 59 if cell is not None:
60 60 cells.append(cell)
61 61 state = u'htmlcell'
62 62 cell_lines = []
63 63 kwargs = {}
64 64 elif line.startswith(u'# <markdowncell>'):
65 65 cell = self.new_cell(state, cell_lines, **kwargs)
66 66 if cell is not None:
67 67 cells.append(cell)
68 68 state = u'markdowncell'
69 69 cell_lines = []
70 70 kwargs = {}
71 71 # VERSIONHACK: plaintext -> raw
72 72 elif line.startswith(u'# <rawcell>') or line.startswith(u'# <plaintextcell>'):
73 73 cell = self.new_cell(state, cell_lines, **kwargs)
74 74 if cell is not None:
75 75 cells.append(cell)
76 76 state = u'rawcell'
77 77 cell_lines = []
78 78 kwargs = {}
79 79 elif line.startswith(u'# <headingcell'):
80 80 cell = self.new_cell(state, cell_lines, **kwargs)
81 81 if cell is not None:
82 82 cells.append(cell)
83 83 cell_lines = []
84 84 m = re.match(r'# <headingcell level=(?P<level>\d)>',line)
85 85 if m is not None:
86 86 state = u'headingcell'
87 87 kwargs = {}
88 88 kwargs['level'] = int(m.group('level'))
89 89 else:
90 90 state = u'codecell'
91 91 kwargs = {}
92 92 cell_lines = []
93 93 else:
94 94 cell_lines.append(line)
95 95 if cell_lines and state == u'codecell':
96 96 cell = self.new_cell(state, cell_lines)
97 97 if cell is not None:
98 98 cells.append(cell)
99 99 ws = new_worksheet(cells=cells)
100 100 nb = new_notebook(worksheets=[ws])
101 101 return nb
102 102
103 103 def new_cell(self, state, lines, **kwargs):
104 104 if state == u'codecell':
105 105 input = u'\n'.join(lines)
106 106 input = input.strip(u'\n')
107 107 if input:
108 108 return new_code_cell(input=input)
109 109 elif state == u'htmlcell':
110 110 text = self._remove_comments(lines)
111 111 if text:
112 112 return new_text_cell(u'html',source=text)
113 113 elif state == u'markdowncell':
114 114 text = self._remove_comments(lines)
115 115 if text:
116 116 return new_text_cell(u'markdown',source=text)
117 117 elif state == u'rawcell':
118 118 text = self._remove_comments(lines)
119 119 if text:
120 120 return new_text_cell(u'raw',source=text)
121 121 elif state == u'headingcell':
122 122 text = self._remove_comments(lines)
123 123 level = kwargs.get('level',1)
124 124 if text:
125 125 return new_heading_cell(source=text,level=level)
126 126
127 127 def _remove_comments(self, lines):
128 128 new_lines = []
129 129 for line in lines:
130 130 if line.startswith(u'#'):
131 131 new_lines.append(line[2:])
132 132 else:
133 133 new_lines.append(line)
134 134 text = u'\n'.join(new_lines)
135 135 text = text.strip(u'\n')
136 136 return text
137 137
138 138 def split_lines_into_blocks(self, lines):
139 139 if len(lines) == 1:
140 140 yield lines[0]
141 141 raise StopIteration()
142 142 import ast
143 143 source = '\n'.join(lines)
144 144 code = ast.parse(source)
145 145 starts = [x.lineno-1 for x in code.body]
146 146 for i in range(len(starts)-1):
147 147 yield '\n'.join(lines[starts[i]:starts[i+1]]).strip('\n')
148 148 yield '\n'.join(lines[starts[-1]:]).strip('\n')
149 149
150 150
151 151 class PyWriter(NotebookWriter):
152 152
153 153 def writes(self, nb, **kwargs):
154 154 lines = [u'# -*- coding: utf-8 -*-']
155 155 lines.extend([
156 156 u'# <nbformat>%i.%i</nbformat>' % (nbformat, nbformat_minor),
157 157 u'',
158 158 ])
159 159 for ws in nb.worksheets:
160 160 for cell in ws.cells:
161 161 if cell.cell_type == u'code':
162 162 input = cell.get(u'input')
163 163 if input is not None:
164 164 lines.extend([u'# <codecell>',u''])
165 165 lines.extend(input.splitlines())
166 166 lines.append(u'')
167 167 elif cell.cell_type == u'html':
168 168 input = cell.get(u'source')
169 169 if input is not None:
170 170 lines.extend([u'# <htmlcell>',u''])
171 171 lines.extend([u'# ' + line for line in input.splitlines()])
172 172 lines.append(u'')
173 173 elif cell.cell_type == u'markdown':
174 174 input = cell.get(u'source')
175 175 if input is not None:
176 176 lines.extend([u'# <markdowncell>',u''])
177 177 lines.extend([u'# ' + line for line in input.splitlines()])
178 178 lines.append(u'')
179 179 elif cell.cell_type == u'raw':
180 180 input = cell.get(u'source')
181 181 if input is not None:
182 182 lines.extend([u'# <rawcell>',u''])
183 183 lines.extend([u'# ' + line for line in input.splitlines()])
184 184 lines.append(u'')
185 185 elif cell.cell_type == u'heading':
186 186 input = cell.get(u'source')
187 187 level = cell.get(u'level',1)
188 188 if input is not None:
189 189 lines.extend([u'# <headingcell level=%s>' % level,u''])
190 190 lines.extend([u'# ' + line for line in input.splitlines()])
191 191 lines.append(u'')
192 192 lines.append('')
193 return unicode('\n'.join(lines))
193 return u'\n'.join(lines)
194 194
195 195
196 196 _reader = PyReader()
197 197 _writer = PyWriter()
198 198
199 199 reads = _reader.reads
200 200 read = _reader.read
201 201 to_notebook = _reader.to_notebook
202 202 write = _writer.write
203 203 writes = _writer.writes
204 204
General Comments 0
You need to be logged in to leave comments. Login now