##// END OF EJS Templates
preserve orig_nbformat when converting 3 to 4...
MinRK -
Show More
@@ -1,208 +1,209 b''
1 """Code for converting notebooks to and from v3."""
1 """Code for converting notebooks to and from v3."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import json
6 import json
7
7
8 from .nbbase import (
8 from .nbbase import (
9 nbformat, nbformat_minor,
9 nbformat, nbformat_minor,
10 NotebookNode,
10 NotebookNode,
11 )
11 )
12
12
13 from IPython.nbformat import v3
13 from IPython.nbformat import v3
14 from IPython.utils.log import get_logger
14 from IPython.utils.log import get_logger
15
15
16
16
17 def upgrade(nb, from_version=3, from_minor=0):
17 def upgrade(nb, from_version=3, from_minor=0):
18 """Convert a notebook to v4.
18 """Convert a notebook to v4.
19
19
20 Parameters
20 Parameters
21 ----------
21 ----------
22 nb : NotebookNode
22 nb : NotebookNode
23 The Python representation of the notebook to convert.
23 The Python representation of the notebook to convert.
24 from_version : int
24 from_version : int
25 The original version of the notebook to convert.
25 The original version of the notebook to convert.
26 from_minor : int
26 from_minor : int
27 The original minor version of the notebook to convert (only relevant for v >= 3).
27 The original minor version of the notebook to convert (only relevant for v >= 3).
28 """
28 """
29 from IPython.nbformat.current import validate, ValidationError
29 from IPython.nbformat.current import validate, ValidationError
30 if from_version == 3:
30 if from_version == 3:
31 # Validate the notebook before conversion
31 # Validate the notebook before conversion
32 try:
32 try:
33 validate(nb, version=from_version)
33 validate(nb, version=from_version)
34 except ValidationError as e:
34 except ValidationError as e:
35 get_logger().error("Notebook JSON is not valid v%i: %s", from_version, e)
35 get_logger().error("Notebook JSON is not valid v%i: %s", from_version, e)
36
36
37 # Mark the original nbformat so consumers know it has been converted.
37 # Mark the original nbformat so consumers know it has been converted
38 nb.pop('orig_nbformat', None)
38 orig_nbformat = nb.pop('orig_nbformat', None)
39 nb.metadata.orig_nbformat = 3
39 nb.metadata.orig_nbformat = orig_nbformat or 3
40
40 # Mark the new format
41 # Mark the new format
41 nb.nbformat = nbformat
42 nb.nbformat = nbformat
42 nb.nbformat_minor = nbformat_minor
43 nb.nbformat_minor = nbformat_minor
43
44
44 # remove worksheet(s)
45 # remove worksheet(s)
45 nb['cells'] = cells = []
46 nb['cells'] = cells = []
46 # In the unlikely event of multiple worksheets,
47 # In the unlikely event of multiple worksheets,
47 # they will be flattened
48 # they will be flattened
48 for ws in nb.pop('worksheets', []):
49 for ws in nb.pop('worksheets', []):
49 # upgrade each cell
50 # upgrade each cell
50 for cell in ws['cells']:
51 for cell in ws['cells']:
51 cells.append(upgrade_cell(cell))
52 cells.append(upgrade_cell(cell))
52 # upgrade metadata
53 # upgrade metadata
53 nb.metadata.pop('name', '')
54 nb.metadata.pop('name', '')
54 # Validate the converted notebook before returning it
55 # Validate the converted notebook before returning it
55 try:
56 try:
56 validate(nb, version=nbformat)
57 validate(nb, version=nbformat)
57 except ValidationError as e:
58 except ValidationError as e:
58 get_logger().error("Notebook JSON is not valid v%i: %s", nbformat, e)
59 get_logger().error("Notebook JSON is not valid v%i: %s", nbformat, e)
59 return nb
60 return nb
60 elif from_version == 4:
61 elif from_version == 4:
61 # nothing to do
62 # nothing to do
62 if from_minor != nbformat_minor:
63 if from_minor != nbformat_minor:
63 nb.metadata.orig_nbformat_minor = from_minor
64 nb.metadata.orig_nbformat_minor = from_minor
64 nb.nbformat_minor = nbformat_minor
65 nb.nbformat_minor = nbformat_minor
65
66
66 return nb
67 return nb
67 else:
68 else:
68 raise ValueError('Cannot convert a notebook directly from v%s to v4. ' \
69 raise ValueError('Cannot convert a notebook directly from v%s to v4. ' \
69 'Try using the IPython.nbformat.convert module.' % from_version)
70 'Try using the IPython.nbformat.convert module.' % from_version)
70
71
71 def upgrade_cell(cell):
72 def upgrade_cell(cell):
72 """upgrade a cell from v3 to v4
73 """upgrade a cell from v3 to v4
73
74
74 code cell:
75 code cell:
75 - remove language metadata
76 - remove language metadata
76 - cell.input -> cell.source
77 - cell.input -> cell.source
77 - update outputs
78 - update outputs
78 """
79 """
79 cell.setdefault('metadata', NotebookNode())
80 cell.setdefault('metadata', NotebookNode())
80 if cell.cell_type == 'code':
81 if cell.cell_type == 'code':
81 cell.pop('language', '')
82 cell.pop('language', '')
82 cell.metadata.collapsed = cell.pop('collapsed')
83 cell.metadata.collapsed = cell.pop('collapsed')
83 cell.source = cell.pop('input')
84 cell.source = cell.pop('input')
84 cell.setdefault('prompt_number', None)
85 cell.setdefault('prompt_number', None)
85 cell.outputs = upgrade_outputs(cell.outputs)
86 cell.outputs = upgrade_outputs(cell.outputs)
86 elif cell.cell_type == 'html':
87 elif cell.cell_type == 'html':
87 # Technically, this exists. It will never happen in practice.
88 # Technically, this exists. It will never happen in practice.
88 cell.cell_type = 'markdown'
89 cell.cell_type = 'markdown'
89 return cell
90 return cell
90
91
91 def downgrade_cell(cell):
92 def downgrade_cell(cell):
92 if cell.cell_type == 'code':
93 if cell.cell_type == 'code':
93 cell.language = 'python'
94 cell.language = 'python'
94 cell.input = cell.pop('source', '')
95 cell.input = cell.pop('source', '')
95 cell.collapsed = cell.metadata.pop('collapsed', False)
96 cell.collapsed = cell.metadata.pop('collapsed', False)
96 cell.outputs = downgrade_outputs(cell.outputs)
97 cell.outputs = downgrade_outputs(cell.outputs)
97 return cell
98 return cell
98
99
99 _mime_map = {
100 _mime_map = {
100 "text" : "text/plain",
101 "text" : "text/plain",
101 "html" : "text/html",
102 "html" : "text/html",
102 "svg" : "image/svg+xml",
103 "svg" : "image/svg+xml",
103 "png" : "image/png",
104 "png" : "image/png",
104 "jpeg" : "image/jpeg",
105 "jpeg" : "image/jpeg",
105 "latex" : "text/latex",
106 "latex" : "text/latex",
106 "json" : "application/json",
107 "json" : "application/json",
107 "javascript" : "application/javascript",
108 "javascript" : "application/javascript",
108 };
109 };
109
110
110 def to_mime_key(d):
111 def to_mime_key(d):
111 """convert dict with v3 aliases to plain mime-type keys"""
112 """convert dict with v3 aliases to plain mime-type keys"""
112 for alias, mime in _mime_map.items():
113 for alias, mime in _mime_map.items():
113 if alias in d:
114 if alias in d:
114 d[mime] = d.pop(alias)
115 d[mime] = d.pop(alias)
115 return d
116 return d
116
117
117 def from_mime_key(d):
118 def from_mime_key(d):
118 """convert dict with mime-type keys to v3 aliases"""
119 """convert dict with mime-type keys to v3 aliases"""
119 for alias, mime in _mime_map.items():
120 for alias, mime in _mime_map.items():
120 if mime in d:
121 if mime in d:
121 d[alias] = d.pop(mime)
122 d[alias] = d.pop(mime)
122 return d
123 return d
123
124
124 def upgrade_output(output):
125 def upgrade_output(output):
125 """upgrade a single code cell output from v3 to v4
126 """upgrade a single code cell output from v3 to v4
126
127
127 - pyout -> execute_result
128 - pyout -> execute_result
128 - pyerr -> error
129 - pyerr -> error
129 - mime-type keys
130 - mime-type keys
130 - stream.stream -> stream.name
131 - stream.stream -> stream.name
131 """
132 """
132 output.setdefault('metadata', NotebookNode())
133 output.setdefault('metadata', NotebookNode())
133 if output['output_type'] in {'pyout', 'display_data'}:
134 if output['output_type'] in {'pyout', 'display_data'}:
134 if output['output_type'] == 'pyout':
135 if output['output_type'] == 'pyout':
135 output['output_type'] = 'execute_result'
136 output['output_type'] = 'execute_result'
136 to_mime_key(output)
137 to_mime_key(output)
137 to_mime_key(output.metadata)
138 to_mime_key(output.metadata)
138 if 'application/json' in output:
139 if 'application/json' in output:
139 output['application/json'] = json.loads(output['application/json'])
140 output['application/json'] = json.loads(output['application/json'])
140 # promote ascii bytes (from v2) to unicode
141 # promote ascii bytes (from v2) to unicode
141 for key in ('image/png', 'image/jpeg'):
142 for key in ('image/png', 'image/jpeg'):
142 if key in output and isinstance(output[key], bytes):
143 if key in output and isinstance(output[key], bytes):
143 output[key] = output[key].decode('ascii')
144 output[key] = output[key].decode('ascii')
144 elif output['output_type'] == 'pyerr':
145 elif output['output_type'] == 'pyerr':
145 output['output_type'] = 'error'
146 output['output_type'] = 'error'
146 elif output['output_type'] == 'stream':
147 elif output['output_type'] == 'stream':
147 output['name'] = output.pop('stream')
148 output['name'] = output.pop('stream')
148 return output
149 return output
149
150
150 def downgrade_output(output):
151 def downgrade_output(output):
151 """downgrade a single code cell output to v3 from v4
152 """downgrade a single code cell output to v3 from v4
152
153
153 - pyout <- execute_result
154 - pyout <- execute_result
154 - pyerr <- error
155 - pyerr <- error
155 - un-mime-type keys
156 - un-mime-type keys
156 - stream.stream <- stream.name
157 - stream.stream <- stream.name
157 """
158 """
158 if output['output_type'] == 'execute_result':
159 if output['output_type'] == 'execute_result':
159 output['output_type'] = 'pyout'
160 output['output_type'] = 'pyout'
160 if 'application/json' in output:
161 if 'application/json' in output:
161 output['application/json'] = json.dumps(output['application/json'])
162 output['application/json'] = json.dumps(output['application/json'])
162 from_mime_key(output)
163 from_mime_key(output)
163 from_mime_key(output.get('metadata', {}))
164 from_mime_key(output.get('metadata', {}))
164 elif output['output_type'] == 'error':
165 elif output['output_type'] == 'error':
165 output['output_type'] = 'pyerr'
166 output['output_type'] = 'pyerr'
166 elif output['output_type'] == 'display_data':
167 elif output['output_type'] == 'display_data':
167 if 'application/json' in output:
168 if 'application/json' in output:
168 output['application/json'] = json.dumps(output['application/json'])
169 output['application/json'] = json.dumps(output['application/json'])
169 from_mime_key(output)
170 from_mime_key(output)
170 from_mime_key(output.get('metadata', {}))
171 from_mime_key(output.get('metadata', {}))
171 elif output['output_type'] == 'stream':
172 elif output['output_type'] == 'stream':
172 output['stream'] = output.pop('name')
173 output['stream'] = output.pop('name')
173 output.pop('metadata')
174 output.pop('metadata')
174 return output
175 return output
175
176
176 def upgrade_outputs(outputs):
177 def upgrade_outputs(outputs):
177 """upgrade outputs of a code cell from v3 to v4"""
178 """upgrade outputs of a code cell from v3 to v4"""
178 return [upgrade_output(op) for op in outputs]
179 return [upgrade_output(op) for op in outputs]
179
180
180 def downgrade_outputs(outputs):
181 def downgrade_outputs(outputs):
181 """downgrade outputs of a code cell to v3 from v4"""
182 """downgrade outputs of a code cell to v3 from v4"""
182 return [downgrade_output(op) for op in outputs]
183 return [downgrade_output(op) for op in outputs]
183
184
184 def downgrade(nb):
185 def downgrade(nb):
185 """Convert a v4 notebook to v3.
186 """Convert a v4 notebook to v3.
186
187
187 Parameters
188 Parameters
188 ----------
189 ----------
189 nb : NotebookNode
190 nb : NotebookNode
190 The Python representation of the notebook to convert.
191 The Python representation of the notebook to convert.
191 """
192 """
192 from IPython.nbformat.current import validate
193 from IPython.nbformat.current import validate
193 # Validate the notebook before conversion
194 # Validate the notebook before conversion
194 validate(nb, version=nbformat)
195 validate(nb, version=nbformat)
195
196
196 if nb.nbformat != 4:
197 if nb.nbformat != 4:
197 return nb
198 return nb
198 nb.nbformat = v3.nbformat
199 nb.nbformat = v3.nbformat
199 nb.nbformat_minor = v3.nbformat_minor
200 nb.nbformat_minor = v3.nbformat_minor
200 cells = [ downgrade_cell(cell) for cell in nb.pop('cells') ]
201 cells = [ downgrade_cell(cell) for cell in nb.pop('cells') ]
201 nb.worksheets = [v3.new_worksheet(cells=cells)]
202 nb.worksheets = [v3.new_worksheet(cells=cells)]
202 nb.metadata.setdefault('name', '')
203 nb.metadata.setdefault('name', '')
203 nb.metadata.pop('orig_nbformat', None)
204 nb.metadata.pop('orig_nbformat', None)
204 nb.metadata.pop('orig_nbformat_minor', None)
205 nb.metadata.pop('orig_nbformat_minor', None)
205
206
206 # Validate the converted notebook before returning it
207 # Validate the converted notebook before returning it
207 validate(nb, version=v3.nbformat)
208 validate(nb, version=v3.nbformat)
208 return nb
209 return nb
General Comments 0
You need to be logged in to leave comments. Login now