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