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